using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Reflection;

namespace Web.Ajax.Controls
{
	[ToolboxData(@"
<{0}:PopupMenu runat=""server"" SourceId=""?"">
</{0}:PopupMenu>")]
	[ControlBuilderAttribute(typeof(PopupMenuBuilder))]
	[ParseChildren(false)] 
	public class PopupMenu : AjaxControl
	{
		#region Rendered
		/// <summary>
		/// Indicates if this PopupMenu has already been rendered.
		/// </summary>
		private bool Rendered = false; 
		#endregion

		#region SourceId
		/// <summary>
		/// The server side Id of the control that will cause the popup menu to appear.
		/// </summary>
		private string sourceId = "";

		public string SourceId
		{
			get { return sourceId; }
			set { sourceId = value; }
		} 
		#endregion
		
		#region ClientSourceId
		/// <summary>
		/// The Client side Id of the control that will cause the popup menu to appear. Readonly.
		/// </summary>
		public string ClientSourceId
		{
			get
			{
				if (Parent.ID == SourceId)					//Is the parent the source control(as would be the case for a sub menu)
					return WebControl.GetJavascriptId(Parent);
				Control c = Parent.FindControl(SourceId);	//Is the source control in the parents naming container.
				if (c != null)
					return WebControl.GetJavascriptId(c);						//No server control found, assume the SourceId is the ClientSourceId
				return SourceId;
			}
		}
		#endregion

        protected override void OnInit(EventArgs e)
        {
            Ajax.RegisterAjaxMethods(this);
            base.OnInit(e);
            Web.Ajax.Page p = Page as Web.Ajax.Page;
            if (p != null)
            {
				p.RegisterJavascriptFile(Resources.Javascript.AjaxControl);
                p.RegisterStyleSheet(Resources.StyleSheets.PopupMenu);
                p.RegisterJavascriptFile(Resources.Javascript.PopupMenu);
            }
        }


		private int leftOffset = 0;
		public int LeftOffset
		{
			get { return leftOffset; }
			set { leftOffset = value; }
		}

		private int topOffset = 0;
		public int TopOffset
		{
			get { return topOffset; }
			set { topOffset = value; }
		}

        private ClientEvent showEvent=ClientEvent.Hover;
        public ClientEvent ShowEvent
        {
            get { return showEvent; }
            set { showEvent = value; }
        }

        private ClientEvent hideEvent=ClientEvent.MouseOut;
        public ClientEvent HideEvent
        {
            get { return hideEvent; }
            set { hideEvent = value; }
        }

        private string side="b";
        public string Side
        {
            get { return side; }
            set { side = value; }
        }


		//the JavascriptId of the ParentMenu
		public string ParentId { get; set; }

        /// <summary>
        /// The signature for the static method used to return the Tree data.
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public delegate void GetDataMethod(PopupMenuInfo Info);
        public GetDataMethod DataMethod;

		#region Render
		/// <summary>
		/// Renders the html for the PopupMenu to the HtmlTextWriter.
		/// </summary>
		/// <param name="output"></param>
		protected override void Render(HtmlTextWriter output)
		{
			if (Rendered||!Visible)
				return;
			Rendered = true;
			string style = "style=\"";
            if (Width != null && !string.IsNullOrEmpty(Width.ToString()))
                style += "width:" + Width.ToString() + ";";
            style += "\"";
            output.Write("<div "+style+" id=\"" + JavascriptId + "\" class=\"PopupMenuPanel\" ");



            if (HideEvent == ClientEvent.MouseOut)
                output.Write(" onmouseout=\"" + JavascriptId + ".OnMouseOut(event,this)\" ");
            output.Write(">");

			if (Browser == Browser.IE6)
				output.Write("<iframe id=\"" + JavascriptId + "Frame\" src=\"resource.axd?Null\" class=\"PopupIE6Background\" frameborder=\"0\" scrolling=\"no\"></iframe>");


            RenderChildren(output);
			
            output.WriteLine("</div>");
            output.WriteLine("<script type=\"text/javascript\">");
			output.WriteLine("var " + JavascriptId + "=new PopupMenu('" + JavascriptId + "',"+LeftOffset.ToString()+","+TopOffset.ToString()+",'"+Side+"');");
            RenderParameters(output);
            if (DataMethod != null)
            {
                RenderProperty(output, "DataMethodType", DataMethod.Method.DeclaringType.AssemblyQualifiedName);
                RenderProperty(output, "DataMethodName", DataMethod.Method.Name);
            }
            RenderProperty(output, "ShowEvent", ShowEvent);
            RenderProperty(output, "HideEvent", HideEvent);
			if (!string.IsNullOrEmpty(ClientSourceId))
			{
				output.WriteLine("if(el('" + ClientSourceId + "'))");
				output.WriteLine("{");
				if (ShowEvent == ClientEvent.Hover)
					output.WriteLine("el('" + ClientSourceId + "').onmouseover=function(){" + JavascriptId + ".Show(el('" + ClientSourceId + "'))};");
				if (ShowEvent == ClientEvent.Click)
					output.WriteLine("el('" + ClientSourceId + "').onclick=function(){" + JavascriptId + ".Show(null)};");
				if (HideEvent == ClientEvent.MouseOut)
					output.WriteLine("el('" + ClientSourceId + "').onmouseout=function(event){" + JavascriptId + ".OnMouseOut(event, el('" + ClientSourceId + "'))};");
				output.WriteLine("}");
			}
            RenderJavascriptId(output);
			if (!string.IsNullOrEmpty(ParentId))
				output.Write(JavascriptId+".SetParent(window."+ParentId+");");
			output.WriteLine("</script>");
		}
		#endregion

        [Ajax]
        public static PopupMenuResponse GetData(PopupMenuRequest request)
        {
            PopupMenuResponse response = new PopupMenuResponse();
            try
            {
                Type Type = System.Type.GetType(request.DataMethodType);
                if (Type == null)
                    throw new Exception("PopupMenu: Invalid Type.");
                MethodInfo Method = Type.GetMethod(request.DataMethodName);
                if (request.PopupMenuInfo.Parameters == null)
                    request.PopupMenuInfo.Parameters = new Parameter[0];
                object o = null;
                o = Method.Invoke(null, new object[] { request.PopupMenuInfo });
                response.Data = request.PopupMenuInfo;
            }
            catch (Exception e)
            {
                if (e.InnerException != null)
                    response.Message = e.InnerException.Message;
                else
                    response.Message = e.Message;
            }
            return response;
        }
	}

	#region PopupMenuBuilder
	/// <summary>
	/// The Control Builder for the Popup Menu Control.
	/// </summary>
	internal class PopupMenuBuilder : ControlBuilder
	{
		public override Type GetChildControlType(string tagName, System.Collections.IDictionary attribs)
		{
			if (tagName.ToLower() == "menuitem")
				return typeof(PopupMenuItem);
			return base.GetChildControlType(tagName, attribs);
		}
	}
	#endregion

    public enum ClientEvent
    {
        Hover,
        Click,
        MouseOut
    }

    public class PopupMenuRequest : AjaxControlRequest
    {
        public PopupMenuInfo PopupMenuInfo;
    }

    public class PopupMenuResponse : AjaxControlResponse
    {
        public PopupMenuInfo Data;
    }

    public class MenuItem
    {
        public string Image;
        public string Text;
        public string OnClick;        

        public MenuItem()
        {
        }

        public MenuItem(string Text)
        {
            this.Text = Text;
        }

        public MenuItem(string Text, string OnClick)
            : this(Text)
        {
            this.OnClick = OnClick;
        }

        public MenuItem(string Text, string OnClick, string Image)
            : this(Text, OnClick)
        {
            this.Image = Image;
        }
    }

    public class PopupMenuInfo : ControlInfo
    {
        public string Html;             //Used if not null
        public Web.Ajax.Controls.MenuItem[] MenuItems;    //Used if Html is null and not null    
    }
}
